/*******************************************************************************
版权声明: Copyright(C) HT-Tech Co., Ltd. 2020-2021. All rights reserved.
文件名称: htcfg.c
文件描述: 配置文件解析
创 建 者: 陈位仅
创建时间: 2024年11月12日
修改历史:
1. 2024年11月12日   陈位仅      创建文件 
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <libconfig.h>

#include "htmacro.h"
#include "htcfg.h"

// 运行参数提示
static void show_usage(char *basename)
{
    char *p = basename;

    // 获取程序名称
    if(p == NULL) {
        p="htssl";
    } else {
        p = strrchr(basename, '/');
        if(p == NULL) {
            p=basename;
        }
    }

    printf("%s:基于GM/T 0024的密钥交换程序.\n", p);
    printf("Usage:%s [OPTION][OPTION-VALUE]|[OPTION][OPTION-VALUE]...\n", p);
    printf("OPTIONs:\n");
    printf("-h --help           显示此帮助信息.\n");
    printf("-v --version        显示版本信息.\n");
    printf("-c --config         指定配置文件路径.\n");

    return;
}

// 命令行参数定义
struct option sslOpt[] = {
    {"version", no_argument, NULL, 'v'},
    {"help", no_argument, NULL, 'h'},
    {"config", required_argument, NULL, 'c'},
};

// 运行参数加载
int htcfg_load(ht_cfg_t *pcfg, int argc, char *argv[])
{
    int opt = 0;

    // 加载命令行参数
    while((opt = getopt_long(argc, argv, "vhd:c:", sslOpt, NULL)) != -1)
    {
        switch(opt)
        {
        case 'v':
            printf("Version:%s\n", SDK_VERSION);
            exit(0);
            break;
        case 'h':
            show_usage(argv[0]);
            exit(0);
            break;
        case 'c':
            pcfg->cfgfile = strdup(optarg);
            break;
        default:
            printf("Invalid argument\n");
            return -1;
            break;
        }
    }

    // 参数校验
    if (NULL == pcfg->cfgfile) {
        printf("程序运行需指定配置文件.\n");
        show_usage(argv[0]);
        return -1;
    }

    return 0;
}


// 终端配置文件解析
int htcfg_parse(ht_cfg_t *pcfg, char *filename)
{
    int rv = 0;
    config_t cfg;           // 配置文件结构体
    const char *version;    // 字符串指针
    int mode;               // 工作模式
    const char *gip;        // 网关IP地址
    int gport;              // 网关服务端口
    const char *sip;        // 主站IP地址
    int sport;              // 主站服务端口
    const char *lip;        // 本地代理IP地址
    int lport;              // 本地代理服务端口
    const char *tun;        // 隧道名称
    const char *rootca;     // 根CA证书
    const char *enccrt;     // 加密证书
    const char *enckey;     // 加密私钥
    const char *signcrt;    // 签名证书
    const char *signkey;    // 签名私钥
    const char *username;   // 终端用户名
    const char *passwd;     // 终端口令
    int type;               // 终端类型
    int active;             // ACL 激活状态
    int heartbeat;          // 心跳间隔时间

    // 参数校验
    if (NULL == filename || NULL == pcfg) {
        return -1;
    }

    // 配置初始化
    config_init(&cfg);

    // 加载配置文件
    rv = config_read_file(&cfg, filename);
    if(rv <= 0) {
        fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg),
        config_error_line(&cfg), config_error_text(&cfg));
        config_destroy(&cfg);
        return -1;
    }

    // 获取版本信息
    rv = config_lookup_string(&cfg, "version", &version);
    if(rv <= 0) {
        fprintf(stderr, "No 'version' setting in configuration file.\n");
        goto end;
    }

    // 获取工作模式
    rv = config_lookup_int(&cfg, "mode", &mode);
    if(rv <= 0) {
        fprintf(stderr, "No 'mode' setting in configuration file");
        goto end;
    }

    // 获取隧道模式网关IP地址
    rv = config_lookup_string(&cfg, "tunnel.addr", &gip);
    if(rv <= 0) {
        fprintf(stderr, "No 'tunnel ip' setting in configuration file.\n");
        goto end;
    }

    // 获取隧道模式网关服务端口
    rv = config_lookup_int(&cfg, "tunnel.port", &gport);
    if (rv <= 0) {
        fprintf(stderr, "No 'tunnel port' setting in configuration file");
        goto end;
    }

    // 获取代理模式网关IP地址
    rv = config_lookup_string(&cfg, "proxy.addr", &sip);
    if(rv <= 0) {
        fprintf(stderr, "No 'proxy server ip' setting in configuration file.\n");
        goto end;
    }

    // 获取代理模式网关服务端口
    rv = config_lookup_int(&cfg, "proxy.port", &sport);
    if (rv <= 0) {
        fprintf(stderr, "No 'proxy server port' setting in configuration file");
        goto end;
    }

    // 获取本地代理IP地址
    rv = config_lookup_string(&cfg, "proxy.local", &lip);
    if(rv <= 0) {
        fprintf(stderr, "No 'proxy local ip' setting in configuration file.\n");
        goto end;
    }

    // 获取本地代理服务端口
    rv = config_lookup_int(&cfg, "proxy.localport", &lport);
    if (rv <= 0) {
        fprintf(stderr, "No 'proxy local port' setting in configuration file");
        goto end;
    }

    if (HT_MODE_TUNNEL == mode || HT_MODE_COMPRE == mode) {
        // 获取隧道名称
        rv = config_lookup_string(&cfg, "tunnel.name", &tun);
        if(rv <= 0) {
            fprintf(stderr, "No 'tunnel name' setting in configuration file.\n");
            goto end;
        }
    }

    // 获取根CA证书文件路径
    rv = config_lookup_string(&cfg, "certificate.rootca", &rootca);
    if(rv <= 0) {
        fprintf(stderr, "No 'root certificate' setting in configuration file.\n");
        goto end;
    }

    // 获取签名证书文件路径
    rv = config_lookup_string(&cfg, "certificate.sgncrt", &signcrt);
    if(rv <= 0) {
        fprintf(stderr, "No 'sign certificate' setting in configuration file.\n");
        goto end;
    }

    // 获取签名私钥文件路径
    rv = config_lookup_string(&cfg, "certificate.sgnkey", &signkey);
    if(rv <= 0) {
        fprintf(stderr, "No 'sign key' setting in configuration file.\n");
        goto end;
    }

    // 获取加密证书文件路径
    rv = config_lookup_string(&cfg, "certificate.enccrt", &enccrt);
    if(rv <= 0) {
        fprintf(stderr, "No 'enc certificate' setting in configuration file.\n");
        goto end;
    }

    // 获取解密密钥文件路径
    rv = config_lookup_string(&cfg, "certificate.enckey", &enckey);
    if(rv <= 0) {
        fprintf(stderr, "No 'enc enckey' setting in configuration file.\n");
        goto end;
    }

    // 获取终端用户名
    rv = config_lookup_string(&cfg, "auth.username", &username);
    if(rv <= 0) {
        fprintf(stderr, "No 'username' setting in configuration file.\n");
        goto end;
    }

    // 获取终端认证口令
    rv = config_lookup_string(&cfg, "auth.password", &passwd);
    if(rv <= 0) {
        fprintf(stderr, "No 'passwd' setting in configuration file.\n");
        goto end;
    }

    // 获取终端类型
    rv = config_lookup_int(&cfg, "auth.type", &type);
    if(rv <= 0) {
        fprintf(stderr, "No 'type' setting in configuration file.\n");
        goto end;
    }

    // 获取ACL 激活状态
    rv = config_lookup_int(&cfg, "aclAccess", &active);
    if(rv <= 0) {
        fprintf(stderr, "No 'aclAccess' setting in configuration file.\n");
        goto end;
    }

    // 获取ACL 激活状态
    rv = config_lookup_int(&cfg, "heartbeat", &heartbeat);
    if(rv <= 0) {
        fprintf(stderr, "No 'heartbeat' setting in configuration file.\n");
        goto end;
    }

    // 配置信息输出
    pcfg->mode = mode;
    pcfg->gip = strdup(gip);
    pcfg->gport = gport;
    pcfg->sip = strdup(sip);
    pcfg->sport = sport;
    pcfg->lip = strdup(lip);
    pcfg->lport = lport;
    pcfg->tunnel = strdup(tun);
    pcfg->rootca = strdup(rootca);
    pcfg->signcrt = strdup(signcrt);
    pcfg->signkey = strdup(signkey);
    pcfg->enccrt = strdup(enccrt);
    pcfg->enckey = strdup(enckey);
    pcfg->username = strdup(username);
    pcfg->passwd = strdup(passwd);
    pcfg->type = type;
    pcfg->active = active;
    pcfg->heartbeat = heartbeat;

end:
    // 释放配置文件
    config_destroy(&cfg);

    return rv;
}

// 更新SSL连接状态
int htcfg_upstate(ht_cfg_t *pcfg, int state)
{
    
    int rv = 0;
    config_t cfg;           // 配置文件结构体
    config_setting_t *pState = NULL;

    // 参数校验
    if (NULL == pcfg) {
        return -1;
    }

    // 配置初始化
    config_init(&cfg);

    // 加载配置文件
    rv = config_read_file(&cfg, pcfg->cfgfile);
    if(rv <= 0) {
        fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg),
        config_error_line(&cfg), config_error_text(&cfg));
        config_destroy(&cfg);
        return -1;
    }

    pState = config_lookup(&cfg, "state");
    if (pState)  {
        config_setting_set_int(pState, state);
    }

    config_write_file(&cfg, pcfg->cfgfile);
    // 释放配置文件
    config_destroy(&cfg);
    return rv;
}

// 配置资源回收
void htcfg_final(ht_cfg_t *pcfg)
{
    if (NULL == pcfg) {
        return;
    }

    safe_free(pcfg->gip, free);
    safe_free(pcfg->sip, free);
    safe_free(pcfg->lip, free);
    safe_free(pcfg->tunnel, free);
    safe_free(pcfg->rootca, free);
    safe_free(pcfg->signcrt, free);
    safe_free(pcfg->signkey, free);
    safe_free(pcfg->enccrt, free);
    safe_free(pcfg->enckey, free);
    safe_free(pcfg->logfile, free);
    safe_free(pcfg->cfgfile, free);
    safe_free(pcfg->username, free);
    safe_free(pcfg->passwd, free);

    return;
}
